From 9d9742f1e56a331f71c6a46b11ccc765621d46c7 Mon Sep 17 00:00:00 2001 From: Michael Natterer Date: Thu, 14 Oct 2010 13:25:23 +0200 Subject: [PATCH] Bug 631599 - Allow to use arbitrary surfaces for offscreen windows Add signal GdkWindow::create-surface which allows to use any surface type as storage for offscreen windows. Test the new signal in tests/gdkoffscreenbox.c --- gdk/gdkinternals.h | 3 +++ gdk/gdkmarshalers.list | 1 + gdk/gdkoffscreenwindow.c | 38 ++++++++++++++++++++++-------- gdk/gdkwindow.c | 50 ++++++++++++++++++++++++++++++++++++++++ gdk/gdkwindow.h | 4 ++++ tests/gtkoffscreenbox.c | 12 ++++++++++ 6 files changed, 98 insertions(+), 10 deletions(-) diff --git a/gdk/gdkinternals.h b/gdk/gdkinternals.h index e2f45d5cf5..e1b458e803 100644 --- a/gdk/gdkinternals.h +++ b/gdk/gdkinternals.h @@ -550,6 +550,9 @@ GType gdk_offscreen_window_get_type (void); void _gdk_offscreen_window_new (GdkWindow *window, GdkWindowAttr *attributes, gint attributes_mask); +cairo_surface_t * _gdk_offscreen_window_create_surface (GdkWindow *window, + gint width, + gint height); /************************************ diff --git a/gdk/gdkmarshalers.list b/gdk/gdkmarshalers.list index ea36baeb88..cb42499721 100644 --- a/gdk/gdkmarshalers.list +++ b/gdk/gdkmarshalers.list @@ -3,4 +3,5 @@ VOID:BOOLEAN VOID:POINTER,POINTER,POINTER OBJECT:VOID OBJECT:DOUBLE,DOUBLE +BOXED:INT,INT VOID:DOUBLE,DOUBLE,POINTER,POINTER diff --git a/gdk/gdkoffscreenwindow.c b/gdk/gdkoffscreenwindow.c index 0cea577379..55d1fad827 100644 --- a/gdk/gdkoffscreenwindow.c +++ b/gdk/gdkoffscreenwindow.c @@ -113,17 +113,11 @@ get_surface (GdkOffscreenWindow *offscreen) if (! offscreen->surface) { GdkWindowObject *private = (GdkWindowObject *) offscreen->wrapper; - cairo_surface_t *similar; - similar = _gdk_drawable_ref_cairo_surface ((GdkWindow *)private->parent); - - offscreen->surface = cairo_surface_create_similar (similar, - /* FIXME: use visual */ - CAIRO_CONTENT_COLOR, - private->width, - private->height); - - cairo_surface_destroy (similar); + g_signal_emit_by_name (private, "create-surface", + private->width, + private->height, + &offscreen->surface); } return offscreen->surface; @@ -155,6 +149,30 @@ gdk_offscreen_window_ref_cairo_surface (GdkDrawable *drawable) return cairo_surface_reference (get_surface (offscreen)); } +cairo_surface_t * +_gdk_offscreen_window_create_surface (GdkWindow *offscreen, + gint width, + gint height) +{ + GdkWindowObject *private = (GdkWindowObject *) offscreen; + cairo_surface_t *similar; + cairo_surface_t *surface; + + g_return_val_if_fail (GDK_IS_OFFSCREEN_WINDOW (private->impl), NULL); + + similar = _gdk_drawable_ref_cairo_surface ((GdkWindow *)private->parent); + + surface = cairo_surface_create_similar (similar, + /* FIXME: use visual */ + CAIRO_CONTENT_COLOR, + width, + height); + + cairo_surface_destroy (similar); + + return surface; +} + void _gdk_offscreen_window_new (GdkWindow *window, GdkWindowAttr *attributes, diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c index 6801900f8a..8be5dcc213 100644 --- a/gdk/gdkwindow.c +++ b/gdk/gdkwindow.c @@ -27,6 +27,8 @@ #include "config.h" +#include + #include "gdkwindow.h" #ifdef GDK_WINDOWING_X11 @@ -185,6 +187,7 @@ enum { PICK_EMBEDDED_CHILD, /* only called if children are embedded */ TO_EMBEDDER, FROM_EMBEDDER, + CREATE_SURFACE, LAST_SIGNAL }; @@ -353,6 +356,18 @@ accumulate_get_window (GSignalInvocationHint *ihint, return g_value_get_object (handler_return) == NULL; } +static gboolean +create_surface_accumulator (GSignalInvocationHint *ihint, + GValue *return_accu, + const GValue *handler_return, + gpointer data) +{ + g_value_copy (handler_return, return_accu); + + /* Stop on the first non-NULL return value */ + return g_value_get_boxed (handler_return) == NULL; +} + static GQuark quark_pointer_window = 0; static void @@ -373,6 +388,8 @@ gdk_window_class_init (GdkWindowObjectClass *klass) drawable_class->get_clip_region = gdk_window_get_clip_region; drawable_class->get_visible_region = gdk_window_get_visible_region; + klass->create_surface = _gdk_offscreen_window_create_surface; + quark_pointer_window = g_quark_from_static_string ("gtk-pointer-window"); @@ -476,6 +493,39 @@ gdk_window_class_init (GdkWindowObjectClass *klass) G_TYPE_DOUBLE, G_TYPE_POINTER, G_TYPE_POINTER); + + /** + * GdkWindow::create-surface: + * @window: the offscreen window on which the signal is emitted + * @width: the width of the offscreen surface to create + * @height: the height of the offscreen surface to create + * + * The ::create-surface signal is emitted when an offscreen window + * needs its surface (re)created, which happens either when the the + * window is first drawn to, or when the window is being + * resized. The first signal handler that returns a non-%NULL + * surface will stop any further signal emission, and its surface + * will be used. + * + * Note that it is not possible to access the window's previous + * surface from within any callback of this signal. Calling + * gdk_offscreen_window_get_surface() will lead to a crash. + * + * Returns: the newly created #cairo_surface_t for the offscreen window + * + * Since: 3.0 + */ + signals[CREATE_SURFACE] = + g_signal_new (g_intern_static_string ("create-surface"), + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GdkWindowObjectClass, create_surface), + create_surface_accumulator, NULL, + _gdk_marshal_BOXED__INT_INT, + CAIRO_GOBJECT_TYPE_SURFACE, + 2, + G_TYPE_INT, + G_TYPE_INT); } static void diff --git a/gdk/gdkwindow.h b/gdk/gdkwindow.h index 5f2c6cbbc3..05a998930e 100644 --- a/gdk/gdkwindow.h +++ b/gdk/gdkwindow.h @@ -489,6 +489,10 @@ typedef struct _GdkWindowObjectClass GdkWindowObjectClass; struct _GdkWindowObjectClass { GdkDrawableClass parent_class; + + cairo_surface_t * (* create_surface) (GdkWindow *window, + gint width, + gint height); }; /* Windows diff --git a/tests/gtkoffscreenbox.c b/tests/gtkoffscreenbox.c index fe84db2109..1c19fd996e 100644 --- a/tests/gtkoffscreenbox.c +++ b/tests/gtkoffscreenbox.c @@ -234,6 +234,14 @@ offscreen_window_from_parent2 (GdkWindow *window, offscreen_x, offscreen_y); } +static cairo_surface_t * +gdk_offscreen_box_create_alpha_image_surface (GdkWindow *offscreen, + gint width, + gint height) +{ + return cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); +} + static void gtk_offscreen_box_realize (GtkWidget *widget) { @@ -323,6 +331,10 @@ gtk_offscreen_box_realize (GtkWidget *widget) gtk_widget_set_parent_window (offscreen_box->child2, offscreen_box->offscreen_window2); gdk_offscreen_window_set_embedder (offscreen_box->offscreen_window2, window); + + g_signal_connect (offscreen_box->offscreen_window2, "create-surface", + G_CALLBACK (gdk_offscreen_box_create_alpha_image_surface), + offscreen_box); g_signal_connect (offscreen_box->offscreen_window2, "to-embedder", G_CALLBACK (offscreen_window_to_parent2), offscreen_box); g_signal_connect (offscreen_box->offscreen_window2, "from-embedder", -- 2.30.2